package com.chat;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;

import java.util.StringTokenizer;


import javax.swing.JOptionPane;





public class Server {

    private ServerChatFrame frame;
   

    private ServerSocket serverSocket;
    private ServerThread serverThread;
    private ArrayList<ClientThread> clients;//客户线程数组

    private boolean isStart = false;//标志服务器是否启动或关闭

 
    private boolean isPressed=false; //ctrl+enter 的判断
    
 
    // 主方法,程序执行入口
    public static void main(String[] args) {

        new Server();

        
    }

    public Server() {
        frame = new ServerChatFrame();
       
       
        // 关闭窗口时事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
			public void windowClosing(WindowEvent e) {
                if (isStart) {
                    closeServer();// 关闭服务器
                }
                System.exit(0);// 退出程序
            }
            
        });

    
        frame.getMsg_Area().addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (KeyEvent.VK_CONTROL == e.getKeyCode()) {
					isPressed = true;
				}
				if (e.getKeyCode() == KeyEvent.VK_ENTER && isPressed) {
					send();
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
				//System.out.println(e.getKeyCode());
				if (KeyEvent.VK_CONTROL == e.getKeyCode() || KeyEvent.VK_ENTER == e.getKeyCode()) {
					isPressed = false;
				}
			}
		});
        
        // 单击发送按钮时事件
        frame.getBtn_send().addActionListener(new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent arg0) {
                send();
            }
        });
        
        // 单击启动服务器按钮时事件
        frame.getBtn_start().addActionListener(new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent e) {

                if (isStart) {
                    JOptionPane.showMessageDialog(frame, "服务器已处于启动状态，不要重复启动！",
                            "错误", JOptionPane.ERROR_MESSAGE);
                    return;
                }
                int max;//人数
                int port;//端口号
                try {
                    try {
                        max = Integer.parseInt(frame.getTxt_max().getText());
                    } catch (Exception e1) {
                        throw new Exception("人数上限为正整数！");
                    }
                    if (max <= 0) {
                        throw new Exception("人数上限为正整数！");
                    }
                    try {
                        port = Integer.parseInt(frame.getTxt_port().getText());
                    } catch (Exception e1) {
                        throw new Exception("端口号为正整数！");
                    }
                    if (port <= 0) {
                        throw new Exception("端口号 为正整数！");
                    }
                    serverStart(max, port);
                    //frame.getContentArea().append("服务器已成功启动! " + "\r\n");
                    JOptionPane.showMessageDialog(frame, "服务器成功启动!");
                    frame.getBtn_start().setEnabled(false);
                    frame.getTxt_max().setEnabled(false);
                    frame.getTxt_port().setEnabled(false);
                    frame.getBtn_stop().setEnabled(true);
                 
                   
                    cmd_users();
                } catch (Exception exc) {
                    JOptionPane.showMessageDialog(frame, exc.getMessage(),
                            "错误", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

        // 单击停止服务器按钮时事件
        frame.getBtn_stop().addActionListener(new ActionListener() {
            @Override
			public void actionPerformed(ActionEvent e) {
                if (!isStart) {
                    JOptionPane.showMessageDialog(frame, "服务器还未启动，无需停止！", "错误",
                            JOptionPane.ERROR_MESSAGE);
                    return;
                }
                try {
                    closeServer();
                    frame.getBtn_start().setEnabled(true);
                    frame.getTxt_max().setEnabled(true);
                    frame.getTxt_port().setEnabled(true);
                    frame.getBtn_stop().setEnabled(false);
                    //frame.getContentArea().append("服务器成功停止!\r\n");
                    JOptionPane.showMessageDialog(frame, "服务器成功停止！");
                } catch (Exception exc) {
                    JOptionPane.showMessageDialog(frame, "停止服务器发生异常！", "错误",
                            JOptionPane.ERROR_MESSAGE);
                }
            }
        });
    }
    
 
    
    /**
     * 群发通知
     */
    public void send() {
        if (!isStart) {
            JOptionPane.showMessageDialog(frame, "服务器还未启动,不能发送消息！", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }

        String message = frame.getMsg_Area().getText().trim();
        if (message == null || message.equals("")) {
            JOptionPane.showMessageDialog(frame, "消息不能为空！", "错误",
                    JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        frame.getContentArea().append("服务器通知 ： "+ "\n"+ message + "\n");
    	message = message.replaceAll("[\\r\\n]", "`");//转换回车换行
            for (int j = clients.size() - 1; j >= 0; j--) {
                
               clients.get(j).getWriter().println("NOTICE#" + message);
               clients.get(j).getWriter().flush();
                   
        }
        
        frame.getMsg_Area().setText("");
    }

    
   
    /**
     * 启动服务器
     *
     * @param max
     * @param port
     * @throws java.net.BindException
     */
    public void serverStart(int max, int port) throws java.net.BindException {
        try {
            clients = new ArrayList<ClientThread>();
            serverSocket = new ServerSocket(port);
            serverThread = new ServerThread(serverSocket, max);
            serverThread.start();//只开启一个监听线程
            isStart = true;
        } catch (BindException e) {
            isStart = false;
            throw new BindException("端口号已被占用，请换一个！");
        } catch (Exception e1) {
            e1.printStackTrace();
            isStart = false;
            throw new BindException("启动服务器异常！");
        }
    }

    /**
     * 关闭服务器
     */
    @SuppressWarnings("deprecation")
    public void closeServer() {
        try {
            if (serverThread != null)
                serverThread.stop();// 停止服务器线程

            for (int i = clients.size() - 1; i >= 0; i--) {
                // 给所有在线用户发送关闭命令
                clients.get(i).getWriter().println("CLOSE");
                clients.get(i).getWriter().flush();
                // 释放资源
                clients.get(i).stop();// 停止此条为客户端服务的线程
                clients.get(i).reader.close();
                clients.get(i).writer.close();
                clients.get(i).socket.close();
                clients.remove(i);
            }
            if (serverSocket != null) {
                serverSocket.close();// 关闭服务器端连接
            }
            
            isStart = false;
           
            cmd_users();
        } catch (IOException e) {
            e.printStackTrace();
            isStart = true;
        }
    }

    
    /**
     * 列出用户
     */
    public void cmd_users(){
    	ServerChatFrame.getAll_listModel().removeAllElements();
    	
        //循环已连接的客户端
        for(int i=0;i<clients.size();i++){
        	ClientThread c = clients.get(i);
        	User u = c.getUser();
        	if(u.getState()==2){
        		ServerChatFrame.getAll_listModel().addElement(u.getName() + "("+u.getIp()+")");
        	}
        	
        }
    }
    
   /**
    * 登陆
    * @param name
    * @param password
    * @return
    */
    
    public int cmd_login(String name,String ip){
    	User user = null;
    	for(int i=0;i<clients.size();i++){
    		ClientThread c = clients.get(i);
    		User u = c.getUser();
    		if(name.equals(u.getName()) && u.getState()==2){
    		
    			return 2;//已有该用户在线状态，无法登陆
    			
    		}else if(ip.equals(u.getIp()) && u.getState()==2){
    			return 0; //已有该ip的 用户登陆
    		}else if(name.equals(u.getName()) && u.getState()==1){
    			user = u;
    		}
    	}
    	user.setState(2);
    	return 1; //登陆
    }
    
    
    /**
     * 服务器线程
     */
    class ServerThread extends Thread {
        private ServerSocket serverSocket;
        private int max;// 人数上限

        // 服务器线程的构造方法
        public ServerThread(ServerSocket serverSocket, int max) {
            this.serverSocket = serverSocket;
            this.max = max;
        }

        @Override
		public void run() {
            while (true) {// 不停的等待客户端的连接，用户登陆之前连接
            	
                try {
                	System.out.println("等待连接........");
                    Socket socket = serverSocket.accept();
                    System.out.println("连接。。");
                    
                    
                    if (clients.size() >= max) {// 如果已达人数上限
                        
                    	BufferedReader r = new BufferedReader(
                                new InputStreamReader(socket.getInputStream()));
                    	PrintWriter  w = new PrintWriter(socket.getOutputStream());
                        // 接收客户端的基本用户信息
                        String inf = r.readLine();
                        StringTokenizer st = new StringTokenizer(inf, "#");
                        User user = new User(st.nextToken(), st.nextToken());
                        
                        // 反馈连接成功信息
                        w.println("MAX#服务器：对不起，" + user.getName()
                                + user.getIp() + "，服务器在线人数已达上限，请稍后尝试连接！");
                        w.flush();
                        
                        w.close();
                        r.close();
                        socket.close();
                        continue;
                    }
                    ClientThread client = new ClientThread(socket);
                    client.start();// 开启对此客户端服务的线程
                    clients.add(client);
                
                   

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    
    
    
    /**
     * 为一个客户端服务的线程
     */
    class ClientThread extends Thread {
        private Socket socket;
        private BufferedReader reader;
        private PrintWriter writer;
        private User user;

        public BufferedReader getReader() {
            return reader;
        }

        public PrintWriter getWriter() {
            return writer;
        }

        public User getUser() {
            return user;
        }

        // 客户端线程的构造方法
        public ClientThread(Socket socket) {
            try {
                this.socket = socket;
                reader = new BufferedReader(new InputStreamReader(socket
                        .getInputStream()));
                writer = new PrintWriter(socket.getOutputStream());
                // 接收客户端的基本用户信息,客户端连接时发送 用户名，ip
                String inf = reader.readLine();
                StringTokenizer st = new StringTokenizer(inf, "#");
                
                user = new User(st.nextToken(), st.nextToken());
                
                user.setState(1);//已连接
              

                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
		@SuppressWarnings("deprecation")
        public void run() {// 不断接收客户端的消息，进行处理。
            String message = null;
            while (true) {
                try {
                    message = reader.readLine();// 接收客户端消息
                    System.out.println("message:"+message);
                    StringTokenizer stringTokenizer = new StringTokenizer(
                            message, "#");
                    String command = stringTokenizer.nextToken();// 命令
                    if (command.equals("CLOSE"))// 下线命令
                    {
                        
                        this.getUser().setState(0);
                        reader.close();
                        writer.close();
                        socket.close();
                        
                       // 删除此条客户端服务线程
                        for (int i = clients.size() - 1; i >= 0; i--) {
                            if (clients.get(i).getUser() == user) {
                                ClientThread temp = clients.get(i);
                                clients.remove(i);// 删除此用户的服务线程
                                
                            }
                        }
                        
                        
                        cmd_users();

                        //反馈用户状态
                        String liststr = "";
                        for (int j = 0; j < ServerChatFrame.getAll_listModel().size(); j++) {
                            liststr += ServerChatFrame.getAll_listModel().get(j) + "#";
                        }
                        // 向所有在线用户发送该用户上线命令
                        for (int j = clients.size()-1 ; j >= 0; j--) {
                            clients.get(j).getWriter().println(
                                    "USERLIST#" + ServerChatFrame.getAll_listModel().size() + "#" + liststr);
                            clients.get(j).getWriter().flush();
                        }
                       
                        return;//关闭线程
                        //处理登陆
                    } else if (command.equals("USERLOGIN")) {
                        String username = stringTokenizer.nextToken();
                     
                        String myIP = stringTokenizer.nextToken();
                     
                        int i = cmd_login(username, myIP);
                        if (1 == i) {
                          
                        	cmd_users();
                           
                            writer.println("USERLOGIN#OK#");
                            writer.flush();
                           

                            //反馈用户状态
                            String temp = "";
                            for (int j = 0; j < ServerChatFrame.getAll_listModel().size(); j++) {
                                temp += ServerChatFrame.getAll_listModel().get(j) + "#";
                            }
                            // 向所有在线用户发送该用户上线命令
                            for (int j = clients.size()-1 ; j >= 0; j--) {
                                clients.get(j).getWriter().println(
                                        "USERLIST#" + ServerChatFrame.getAll_listModel().size() + "#" + temp);
                                clients.get(j).getWriter().flush();
                            }

                        } else if (2 == i) {//已有该昵称登陆
                            writer.println("USERLOGIN#NAMELOGIN");
                            writer.flush();
                        } else {//已有该IP用户登陆
                            writer.println("USERLOGIN#IPLOGIN");
                            writer.flush();

                        }
                        
                    } 
                
                    else if(command.equals("FILE")){//转发传输文件信息
                    	dispatcherFile(message);
                    } else {
                        dispatcherMessage(message);// 转发消息
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        // 转发消息
        public void dispatcherMessage(String message) {
            StringTokenizer stringTokenizer = new StringTokenizer(message, "#");
            String cmd = stringTokenizer.nextToken();
            String source = stringTokenizer.nextToken();
            String owner = stringTokenizer.nextToken();//发送者
            String content = stringTokenizer.nextToken();
            if (source.equals("ALL")) {// 群发
                message = owner + "(群发)：" + content;
                frame.getContentArea().append(message + "\r\n");
                for (int i = clients.size() - 1; i >= 0; i--) {
                    clients.get(i).getWriter().println(message);
                    clients.get(i).getWriter().flush();
                }
            } else {
                for (int i = clients.size() - 1; i >= 0; i--) {
                	//System.out.println(clients.get(i).user.getName()+"---"+source);
                    if (clients.get(i).user.getName().equals(source)) {
                    	
                        clients.get(i).getWriter().println("MESSAGE#"+owner + "#" + content);
                        clients.get(i).getWriter().flush();
                        
                    }
                   
                }
            }
        }
        
        // 转发 传输文件信息
        public void dispatcherFile(String message) {
            StringTokenizer stringTokenizer = new StringTokenizer(message, "#");
            String cmd = stringTokenizer.nextToken();
            String port = stringTokenizer.nextToken();
            String fileName = stringTokenizer.nextToken();
            String fileLen = stringTokenizer.nextToken();
            String toUser = stringTokenizer.nextToken();
            String fromUser = stringTokenizer.nextToken();//发送者
            String fromIP = stringTokenizer.nextToken();
                for (int i = clients.size() - 1; i >= 0; i--) {
                	
                    if (clients.get(i).user.getName().equals(toUser)) {
                    	
                        clients.get(i).getWriter().println("FILE#"+port+"#"+fileName+"#"+fileLen+"#"
                        		+fromUser+"#"+fromIP);
                        clients.get(i).getWriter().flush();
                        return;
                    }
                   
                }
            //已离线
            writer.println("LEAVE#"+toUser);
            writer.flush();
        }
    }
}
